#include "CpuControlledObject.h"
#include "include.h"
#include "Grenade.h"
#include "Ghost.h"
#define TEXTURE_FILE "./Images/confederate.bmp"
#define PANIC_FILE "./Images/confederatepanic.bmp"
#define POSE_FILE "./Images/lincolnpose.bmp"
#define FORCE_DAMAGE_DENOM 100000.0
CpuControlledObject::CpuControlledObject(TextureManager * textureManager,
						 Vector2D position, 
						 float mass,
						 Vector2DList * waypoints,
						 Object * target,
						 Weapon * weapon,
						 Vector2D size,
						 char * textureFile,
						 char * panicFile)
:ControlledObject( textureManager, position, Vector2D(0,0),Vector2D(0,0),0.0,0.0,0.0,mass,false)
{
	printf("CpuControlledObject(), new textures\n");
	forceDamageDenominator = FORCE_DAMAGE_DENOM;
	this->textureManager = textureManager;
	this->target = target;
	this->weapon = weapon;
	if(this->weapon)
	{
		this->weapon->owner = this;
	}
	material = new Material("CpuEnemyTexture",0,0,true,0.1,-1);
	freeWander = true;
	wanderRight = false;
	consecutiveFailures = 0;
	failedLast = false;
	currentWaypoint = 0;
	this->waypoints = waypoints;
	if(waypoints)
		currentWaypoint = waypoints->head;
	else
		currentWaypoint = NULL;
	lastDistance = 100000.0;
	stagnantTime = 0.0;
	giveUpTime = 1.0;
	desiredSpeed = 50.0;
	objectId = CONTROLLEDOBJECT_CLASS;

	Vector2D halfSize = size * 0.5;
	vertices[0] = Vector2D(-halfSize.x, halfSize.y);
	vertices[1] = Vector2D(halfSize.x, halfSize.y);
	vertices[2] = Vector2D(halfSize.x, -halfSize.y);
	vertices[3] = Vector2D(-halfSize.x, -halfSize.y);
	
	imageVertices = (Vector2D *)malloc(sizeof(Vector2D) * 4);
	imageVertices[0] = Vector2D(-halfSize.x, halfSize.y);
	imageVertices[1] = Vector2D(halfSize.x, halfSize.y);
	imageVertices[2] = Vector2D(halfSize.x, -halfSize.y);
	imageVertices[3] = Vector2D(-halfSize.x, -halfSize.y);
	
	animationManager = NULL;
	normalAnimation = NULL;
	panicAnimation = NULL;
	textureVertices = (Vector2D *)malloc(sizeof(Vector2D) * 4);
	textureVertices[0] = Vector2D(0,1);
	textureVertices[1] = Vector2D(1,1);
	textureVertices[2] = Vector2D(1,0);
	textureVertices[3] = Vector2D(0,0);
	printf("loading textures\n");
	if(textureManager)
	{
		if(!textureManager->LoadTexture(textureFile))
			printf("Loading %s failed!", textureFile);
		if(!textureManager->LoadTexture(panicFile))
			printf("Loading %s failed!", panicFile);
		if(!textureManager->LoadTexture(GHOST_TEXTURE))
			printf("Loading %s failed!", GHOST_TEXTURE);
		if(!textureManager->LoadTexture(DUST_FILE))
		{
			printf("Failed to load %s\n", DUST_FILE);
		}
		textureIndex = textureManager->TextureIndex(textureFile);
		normalTextureIndex = textureIndex;
		panicTextureIndex = textureManager->TextureIndex(panicFile);
		poseIndex = panicTextureIndex;
	}	
	
}			
CpuControlledObject::CpuControlledObject( TextureManager * textureManager,
						 Vector2D position, 
						 float mass,
						 Vector2DList * waypoints,
						 Object * target)
:ControlledObject( textureManager, position, Vector2D(0,0),Vector2D(0,0),0.0,0.0,0.0,mass,false)
{
	forceDamageDenominator = FORCE_DAMAGE_DENOM;
	weapon = NULL;//new Grenade(textureManager, this, 60000.0, .70, 5000.0, 0.5);
	this->textureManager = textureManager;
	this->target = target;
	material = new Material("CpuEnemyTexture",0,0,true,0.1,-1);
	freeWander = false;
	wanderRight = false;
	consecutiveFailures = 0;
	failedLast = false;
	currentWaypoint = 0;
	this->waypoints = waypoints;
	currentWaypoint = waypoints->head;
	lastDistance = 100000.0;
	stagnantTime = 0.0;
	giveUpTime = 1.0;
	desiredSpeed = 50.0;
	objectId = CONTROLLEDOBJECT_CLASS;

	vertices[0] = Vector2D(-2.0, 5.0);
	vertices[1] = Vector2D(2.0, 5.0);
	vertices[2] = Vector2D(2.0, -5.0);
	vertices[3] = Vector2D(-2.0, -5.0);
	
	(Vector2D *)malloc(sizeof(Vector2D) * 4);
	imageVertices[0] = Vector2D(-5.0, 5.0);
	imageVertices[1] = Vector2D(5.0, 5.0);
	imageVertices[2] = Vector2D(5.0, -5.0);
	imageVertices[3] = Vector2D(-5.0, -5.0);
	
	InitObject();
}
void CpuControlledObject::InitObject()
{
	
	printf("CpuControlledObject::InitObject()\n");
	int * frameSequence = (int *)malloc(sizeof(int)*8);
	frameSequence[0] = 6;
	frameSequence[1] = 7;
	frameSequence[2] = 8;
	frameSequence[3] = 3;
	frameSequence[4] = 4;
	frameSequence[5] = 3;
	frameSequence[6] = 5;
	frameSequence[7] = 0;
	movingTimeModifier = 2.0;
	normalAnimation = new AnimationManager(0.001, frameSequence, 8, 3, 3);
	
	frameSequence = (int *)malloc(sizeof(int)*3);
	frameSequence[0] = 6;
	frameSequence[1] = 7;
	frameSequence[2] = 8;
	panicAnimation = new AnimationManager(0.001, frameSequence, 3, 3, 3);
	animationManager = normalAnimation;
	if(textureManager)
	{
		if(!textureManager->LoadTexture(TEXTURE_FILE))
			printf("Loading %s failed!", TEXTURE_FILE);
		if(!textureManager->LoadTexture(PANIC_FILE))
			printf("Loading %s failed!", PANIC_FILE);
		if(!textureManager->LoadTexture(GHOST_TEXTURE))
			printf("Loading %s failed!", GHOST_TEXTURE);
		if(!textureManager->LoadTexture(DUST_FILE))
		{
			printf("Failed to load %s\n", DUST_FILE);
		}
		textureIndex = textureManager->TextureIndex(TEXTURE_FILE);
		normalTextureIndex = textureIndex;
		panicTextureIndex = textureManager->TextureIndex(PANIC_FILE);
		poseIndex = panicTextureIndex;
	}	
}
CpuControlledObject::CpuControlledObject(TextureManager * textureManager,
						 Vector2D position, 
						 float mass,
						 Object * target,
						 Weapon * weapon)
:ControlledObject( textureManager, position, Vector2D(0,0),Vector2D(0,0),0.0,0.0,0.0,mass,false)
{
	this->textureManager = textureManager;
	this->target = target;
	this->weapon = weapon;
	if(this->weapon)
	{
		printf("doin it\n");
		this->weapon->owner = this;
	}
	printf("did it\n");
	material = new Material("CpuEnemyTexture",0,0,true,0.1,-1);
	freeWander = true;
	wanderRight = false;
	consecutiveFailures = 0;
	failedLast = false;
	currentWaypoint = 0;
	this->waypoints = NULL;
	currentWaypoint = NULL;
	lastDistance = 100000.0;
	stagnantTime = 0.0;
	giveUpTime = 1.0;
	desiredSpeed = 50.0;
	objectId = CONTROLLEDOBJECT_CLASS;

	vertices[0] = Vector2D(-2.0, 5.0);
	vertices[1] = Vector2D(2.0, 5.0);
	vertices[2] = Vector2D(2.0, -5.0);
	vertices[3] = Vector2D(-2.0, -5.0);
	
	imageVertices = (Vector2D *)malloc(sizeof(Vector2D) * 4);
	imageVertices[0] = Vector2D(-5.0, 5.0);
	imageVertices[1] = Vector2D(5.0, 5.0);
	imageVertices[2] = Vector2D(5.0, -5.0);
	imageVertices[3] = Vector2D(-5.0, -5.0);
	InitObject();
	
}
CpuControlledObject::CpuControlledObject( TextureManager * textureManager,
						 Vector2D position, 
						 float mass,
						 Object * target)
:ControlledObject( textureManager, position, Vector2D(0,0),Vector2D(0,0),0.0,0.0,0.0,mass,false)
{
	this->textureManager = textureManager;
	this->target = target;
	weapon = new Grenade(textureManager, this, 60000.0, .70, 5000, 0.5);//3500.0, 0.2);
	material = new Material("CpuEnemyTexture",0,0,true,0.1,-1);
	freeWander = true;
	wanderRight = false;
	consecutiveFailures = 0;
	failedLast = false;
	currentWaypoint = 0;
	this->waypoints = NULL;
	currentWaypoint = NULL;
	lastDistance = 100000.0;
	stagnantTime = 0.0;
	giveUpTime = 1.0;
	desiredSpeed = 50.0;
	objectId = CONTROLLEDOBJECT_CLASS;

	vertices[0] = Vector2D(-2.0, 5.0);
	vertices[1] = Vector2D(2.0, 5.0);
	vertices[2] = Vector2D(2.0, -5.0);
	vertices[3] = Vector2D(-2.0, -5.0);
	
	imageVertices = (Vector2D *)malloc(sizeof(Vector2D) * 4);
	imageVertices[0] = Vector2D(-5.0, 5.0);
	imageVertices[1] = Vector2D(5.0, 5.0);
	imageVertices[2] = Vector2D(5.0, -5.0);
	imageVertices[3] = Vector2D(-5.0, -5.0);
	
	InitObject();
}
CpuControlledObject::~CpuControlledObject()
{
	printf("deleting cpu controlled object\n");
	if(waypoints)
		delete(waypoints);
	waypoints = NULL;
	printf("dcco3\n");
	if(material)
		delete(material);
	material = NULL;
	if(normalAnimation)
		delete(normalAnimation);
	normalAnimation = NULL;
	printf("dcco4\n");
	if(panicAnimation)
		delete(panicAnimation);
	panicAnimation = NULL;
	animationManager = NULL;
	printf("dcco5\n");
	if(weapon)
		delete(weapon);
	weapon = NULL;
	numVertices = 0;
	printf("done deleting cpu controlled object\n");
}
bool CpuControlledObject::GetFreeRotate()
{
	//printf("CpuControlledObject::GetFreeRotate() isNotOnGroundCount = %d\n", isNotOnGroundCount);
	//printf("CpuControlledObject::GetFreeRotate() angularVelocity = %f\n", angularVelocity);
	return abs(angularVelocity) > 10.0 || isNotOnGroundCount >= 10;
}
Vector2D * CpuControlledObject::GetWallPoseCoordinates()
{
	Vector2D * texCoord = (Vector2D *)malloc(4 * sizeof(Vector2D));
	texCoord[0] = Vector2D(.333,.333);
	texCoord[1] = Vector2D(0, .333);
	texCoord[2] = Vector2D(0, 0);
	texCoord[3] = Vector2D(.333, 0);
	return texCoord;
}
float CpuControlledObject::GetAnimationSpeed()
{
	
	if(isOnGround)
	{
		if(velocity.Magnitude() > 0.0)
			return movingTimeModifier/velocity.Magnitude();
		return -1;
	}
	else
	{
		return 0.05;
	}
}
float CpuControlledObject::MoveToward(Vector2D destination)
{
	Vector2D direction = destination - position;
	Vector2D right = Vector2D(1,0);
	float horizontalDistance = right.dot(direction);
	
	float speed = velocity.Magnitude();
	
	if(horizontalDistance > 0)
	{
		if(abs(speed - desiredSpeed) > 10)
		{
			if(speed < desiredSpeed)
				MoveRight();
			else
				MoveLeft();
		}
	}
	else
	{
		if(abs(speed - desiredSpeed) > 10)
		{
			if(speed < desiredSpeed)
				MoveLeft();
			else
				MoveRight();
		}
	}
	return abs(horizontalDistance);
	
}
bool CpuControlledObject::AttackThink(double elapsedTime)
{
	if(weapon)
	{
		//printf("Calling weapon think\n");
		weapon->Think(elapsedTime, target, isOnGround);
	}
	return false;
}
void CpuControlledObject::Wander(double elapsedTime)
{
	Vector2D destination;
	if(freeWander)
	{
		if(wanderRight)
			destination = Vector2D(100000000.0,position.y);
		else
			destination = Vector2D(-100000000.0,position.y);
	}
	else
	{
		destination = *(currentWaypoint->payload);
	}
	
	float horizontalDistance = MoveToward(destination);
	
	if(horizontalDistance > lastDistance || lastDistance - horizontalDistance < 1.0)
	{
		stagnantTime += elapsedTime;
	}
	else
	{
		stagnantTime = 0.0;
		lastDistance = horizontalDistance;
	}
	
	if(horizontalDistance < 10.0 || stagnantTime > giveUpTime)
	{
		//we either got to the waypoint, or we've been stuck for too long and are giving up
		
		if(stagnantTime > giveUpTime && !freeWander)
		{
			failedLast = true;
			consecutiveFailures++;
			
			if(consecutiveFailures > 4)
			{
				consecutiveFailures = 0;
				failedLast = false;
				freeWander = true;
				wanderRight = true;
			}
		}
		else if(freeWander)
		{
			wanderRight = !wanderRight;
		}
		else
		{
			failedLast = false;
			consecutiveFailures = 0;
			currentWaypoint = currentWaypoint->next;
			
			if(currentWaypoint == NULL)
			{
				currentWaypoint = waypoints->head;
			}
		}
		
		stagnantTime = 0.0;
		lastDistance = 1000000000.0;
	}
}
void CpuControlledObject::ControlledObjectThinkEntryPoint(double elapsedTime)
{
		
	if(health <= 0)
	{
		letMeGo = true;
		
		if(velocity.Magnitude() < 100)
		{
			if(objectToDestroy != this)
				objectToCreate = new Ghost(textureManager, position, 3.0);
			objectToDestroy = this;
			return;
		}
	}
	//printf("checking for weapon\n");
	if(AttackThink(elapsedTime))
		return;
	
	Wander(elapsedTime);
	
	if(isNotOnGroundCount < 10)
	{
		textureIndex = normalTextureIndex;
		animationManager = normalAnimation;
	}
	else
	{
		textureIndex = panicTextureIndex;
		animationManager = panicAnimation;
	}
}

void CpuControlledObject::ControlledObjectDrawEntryPoint()
{
	CpuControlledObjectDrawEntryPoint();
	
	if(waypoints == NULL)
		return;
		
	glDisable(GL_TEXTURE_2D);
	glColor3f(1,1,1);
	glBegin(GL_LINES);
	
	List<Vector2D> * search = waypoints->head;
	int i = 0;
	while(search)
	{
		if(search->payload)
		{
			glVertex2f(search->payload->x, search->payload->y);
			if(i > 0 && search->next)
			{
				glVertex2f(search->payload->x, search->payload->y);
			}
		}
		i++;
		search = search->next;
	}
	glEnd();
	
}
void CpuControlledObject::CpuControlledObjectDrawEntryPoint()
{
}	
void CpuControlledObject::MoveRight()
{
	Vector2D right = vertices[1] - vertices[0];
	right = !right;
	float rightSpeed = right.dot(velocity);
	if(rightSpeed > 500)
		return;
	movingRight = true;
	isOnLeftWall = false;
	if(isOnGround)
	{
		float multiplier = velocity.Magnitude() * MOVE_MULTIPLIER;
		if(multiplier > MAX_MOVE_FORCE)
			multiplier = MAX_MOVE_FORCE;
		else if(multiplier < abs(GRAVITATIONAL_FORCE) * mass)
			multiplier = abs(GRAVITATIONAL_FORCE) * mass;
		AddForce(right * multiplier * mass);
	}
}
void CpuControlledObject::MoveLeft()
{
	isOnRightWall = false;
	Vector2D left = vertices[0] - vertices[1];
	left = !left;
	float leftSpeed = left.dot(velocity);
	if(leftSpeed > 500)
		return;
	movingLeft = true;
	if(isOnGround)
	{
		float multiplier = velocity.Magnitude() * MOVE_MULTIPLIER;
		if(multiplier > MAX_MOVE_FORCE)
			multiplier = MAX_MOVE_FORCE;
		else if(multiplier < abs(GRAVITATIONAL_FORCE) * mass)
			multiplier = abs(GRAVITATIONAL_FORCE) * mass;
		AddForce(left * multiplier * mass);
	}
}
/*void CpuControlledObject::Jump()
{
}*/